home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / VIEWERS / MSDOS / GIFLIB12.ZIP / UTIL / GIF2BGI.C next >
C/C++ Source or Header  |  1991-05-12  |  29KB  |  942 lines

  1. /*****************************************************************************
  2. *   "Gif-Lib" - Yet another gif library.                     *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 0.1, Jul. 1989   *
  5. ******************************************************************************
  6. * Program to display GIF file using the BGI device indepedent routines       *
  7. * Options:                                     *
  8. * -q : quite printing mode.                             *
  9. * -d BGI path : specify the directory where to look for bgi drivers.         *
  10. * -u BGIUserDriverName.Mode : use user driver instead of auto detection.     *
  11. * -z factor : zoom the pixels by the given factor.                 *
  12. * -b : beeps disabled.                                 *
  13. * -h : on line help.                                 *
  14. *                                         *
  15. *   In this file Screen refers to GIF file screen, while Device to BGI size. *
  16. ******************************************************************************
  17. * History:                                     *
  18. * 31 Jul 90 - Version 1.0 by Gershon Elber.                     *
  19. *****************************************************************************/
  20.  
  21. #include <graphics.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <conio.h>
  25. #include <ctype.h>
  26. #include <alloc.h>
  27. #include <string.h>
  28. #include <io.h>
  29. #include <dos.h>
  30. #include <bios.h>
  31. #include <fcntl.h>
  32. #include "gif_lib.h"
  33. #include "getarg.h"
  34.  
  35. #define PROGRAM_NAME    "Gif2BGI"
  36.  
  37. #define KEY_LEFT    256      /* Key Codes returned for operational keys */
  38. #define KEY_RIGHT    257      /* as return by the GetKey routine.         */
  39. #define KEY_UP        258
  40. #define KEY_DOWN    259
  41. #define KEY_RETURN    260
  42. #define KEY_DELETE    261
  43. #define KEY_INSERT    262
  44. #define KEY_BSPACE    263
  45. #define KEY_ESC        264
  46. #define KEY_HOME    265
  47. #define KEY_END        266
  48. #define KEY_PGUP    267
  49. #define KEY_PGDN    268
  50.  
  51. #define SET_POSITION_RESET    0        /* Situations need positionings: */
  52. #define SET_POSITION_ZOOM_U    1
  53. #define SET_POSITION_ZOOM_D    2
  54. #define SET_POSITION_PAN    3
  55.  
  56. #define CURSOR_TEXT_X    120
  57.  
  58. #define BGI_USER_INSTALL    999    /* BGI User installed driver device. */
  59.  
  60. #define MIN(x, y)    ((x) < (y) ? (x) : (y))
  61.  
  62. extern unsigned int
  63.     _stklen = 16384;                 /* Increase default stack size. */
  64.  
  65. static char
  66.     *VersionStr =
  67.     PROGRAM_NAME
  68.     GIF_LIB_VERSION
  69.     "    Gershon Elber,    "
  70.     __DATE__ ",   " __TIME__ "\n"
  71.     "(C) Copyright 1989 Gershon Elber, Non commercial use only.\n";
  72. static char
  73.     *CtrlStr =
  74.     PROGRAM_NAME
  75.     " q%- d%-BGI|Directory!s u%-UserBGIDrv.Mode!s z%-ZoomFactor!d b%- h%- GifFile!*s";
  76. static char
  77.     *GifFileName,
  78.     *BGIPath = "",
  79.     *BGIUserDriverName = NULL;
  80.  
  81. /* Make some variables global, so we could access them faster: */
  82. static int
  83.     ImageNum = 0,
  84.     BackGround = 0,
  85.     ForeGround = 1,               /* As close to white as possible. */
  86.     BeepsDisabled = FALSE,
  87.     ZoomFactor = 1,
  88.     MaximumScreenHeight = 1,
  89.     BGIUserDriverMode = -1,
  90.     DeviceMaxX = 640, DeviceMaxY = 400,          /* Physical device dimensions. */
  91.     ScreenWidth = 320, ScreenHeight = 200,         /* Gif image screen size. */
  92.     InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
  93.     InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
  94. static GifColorType
  95.     *ColorMap;
  96.  
  97. static int huge detectVGA(void);
  98. static void BGIInstallUserDriver(char *BGIUserDriverNameMode);
  99. static void DisplayScreen(GifRowType *ScreenBuffer, GifFileType *GifFile);
  100. static void PrintSettingStatus(GifFileType *GifFile);
  101. static void CPrintStr(char *Str, int y);
  102. static void SetPosition(int Why,
  103.                 int *ScreenLeft, int *ScreenTop,
  104.                 int *DeviceLeft, int *DeviceTop,
  105.                 int MoveX,       int MoveY);
  106. static void DrawScreen(GifRowType *ScreenBuffer,
  107.         int ScreenLeft, int ScreenTop, int DeviceLeft, int DeviceTop);
  108. static void DoCursorMode(GifRowType *ScreenBuffer,
  109.         int ScreenLeft, int ScreenTop, int DeviceLeft, int DeviceTop);
  110. static int MyKbHit(void);
  111. static int MyGetCh(void);
  112. static int GetKey(void);
  113. static void Tone(int Frequency, int Time);
  114.  
  115. /******************************************************************************
  116. * Interpret the command line and scan the given GIF file.              *
  117. ******************************************************************************/
  118. void main(int argc, char **argv)
  119. {
  120.     int    i, j, k, Error, NumFiles, Size, Row, Col, Width, Height, ExtCode,
  121.     Count, ColorMapSize, GraphDriver, GraphMode, Sum,
  122.     HelpFlag = FALSE,
  123.     BGIPathFlag = FALSE,
  124.     BGIUserDriverFlag = FALSE,
  125.     ZoomFlag = FALSE;
  126.     GifRecordType RecordType;
  127.     GifByteType *Extension;
  128.     char Str[80], *BGIUserDriverNameMode,
  129.     **FileName = NULL;
  130.     GifRowType *ScreenBuffer;
  131.     GifFileType *GifFile;
  132.     struct text_info TextInfo;      /* So we can restore starting text mode. */
  133.  
  134.     if ((Error = GAGetArgs(argc, argv, CtrlStr,
  135.         &GifQuitePrint, &BGIPathFlag, &BGIPath,
  136.         &BGIUserDriverFlag, &BGIUserDriverNameMode,
  137.         &ZoomFlag, &ZoomFactor,
  138.         &BeepsDisabled, &HelpFlag,
  139.         &NumFiles, &FileName)) != FALSE ||
  140.         (NumFiles > 1 && !HelpFlag)) {
  141.     if (Error)
  142.         GAPrintErrMsg(Error);
  143.     else if (NumFiles > 1)
  144.         GIF_MESSAGE("Error in command line parsing - one GIF file please.");
  145.     GAPrintHowTo(CtrlStr);
  146.     exit(1);
  147.     }
  148.  
  149.     if (HelpFlag) {
  150.     fprintf(stderr, VersionStr);
  151.     GAPrintHowTo(CtrlStr);
  152.     exit(0);
  153.     }
  154.  
  155.     if (BGIUserDriverFlag) {
  156.     /* Use the driver supplied by the user! */
  157.         BGIInstallUserDriver(BGIUserDriverNameMode);
  158.         installuserdriver(BGIUserDriverName, detectVGA);
  159.     GraphDriver = BGI_USER_INSTALL;
  160.     }
  161.     else {
  162.         /* Sense type of display we have and attempt to load right driver. */
  163.         detectgraph(&GraphDriver, &GraphMode);
  164.         if (GraphDriver < 0)
  165.         GIF_EXIT("BGI Auto detect: No graphics device detected.");
  166.     }
  167.  
  168.     /* Put in the following any graphic driver specific setup: */
  169.     switch (GraphDriver) {
  170.     case CGA:
  171.         GraphMode = CGAHI;
  172.         break;
  173.     case EGA:
  174.         GraphMode = EGAHI;
  175.         break;
  176.     case EGA64:
  177.         GraphMode = EGA64HI;
  178.         break;
  179.     case EGAMONO:
  180.         GraphMode = EGAMONOHI;
  181.         break;
  182.     case HERCMONO:
  183.         GraphMode = HERCMONOHI;
  184.         break;
  185.     case VGA:
  186.         GraphMode = VGAHI;
  187.         break;
  188.     case BGI_USER_INSTALL:
  189.         GraphDriver = DETECT;
  190.         GraphMode = BGIUserDriverMode;
  191.         break;
  192.     default:
  193.         GIF_EXIT("Requested graphic device is not supported.");
  194.         break;
  195.     }
  196.  
  197.     if (NumFiles == 1) {
  198.     GifFileName = *FileName;
  199.     if ((GifFile = DGifOpenFileName(*FileName)) == NULL) {
  200.         PrintGifError();
  201.         exit(-1);
  202.     }
  203.     }
  204.     else {
  205.     /* Use the stdin instead: */
  206.     GifFileName = "Stdin";
  207.     setmode(0, O_BINARY);
  208.     if ((GifFile = DGifOpenFileHandle(0)) == NULL) {
  209.         PrintGifError();
  210.         exit(-1);
  211.     }
  212.     }
  213.  
  214.     /* Allocate the screen as vector of column of rows. We cannt allocate    */
  215.     /* the all screen at once, as this broken minded CPU can allocate up to  */
  216.     /* 64k at a time and our image can be bigger than that:             */
  217.     /* Note this screen is device independent - its the screen as defined by */
  218.     /* the GIF file parameters itself.                         */
  219.     if ((ScreenBuffer = (GifRowType *)
  220.     malloc(GifFile -> SHeight * sizeof(GifRowType *))) == NULL)
  221.         GIF_EXIT("Failed to allocate memory required, aborted.");
  222.  
  223.     Size = GifFile -> SWidth * sizeof(GifPixelType);/* Size in bytes of one row.*/
  224.     if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL)    /* First row. */
  225.     GIF_EXIT("Failed to allocate memory required, aborted.");
  226.  
  227.     for (i = 0; i < GifFile -> SWidth; i++)  /* Set its color to BackGround. */
  228.     ScreenBuffer[0][i] = GifFile -> SBackGroundColor;
  229.     MaximumScreenHeight = GifFile -> SHeight - 1;
  230.     for (i = 1; i < GifFile -> SHeight; i++) {
  231.     /* Allocate the other rows, and set their color to background too: */
  232.     if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL) {
  233.         if (i > 30) {
  234.         /* Free some memory for the BGI driver and auxilary. */
  235.         for (j = 1; j < 28; j++)
  236.                 free((char *) ScreenBuffer[i - j]);
  237.             MaximumScreenHeight = i - 28;
  238.             fprintf(stderr, "\n%s: Failed to allocate all memory required, last line %d.\n",
  239.             PROGRAM_NAME, MaximumScreenHeight);
  240.             break;
  241.         }
  242.         else
  243.         GIF_EXIT("Failed to allocate memory required, aborted.");
  244.     }
  245.  
  246.     memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
  247.     }
  248.  
  249.     /* Scan the content of the GIF file and load the image(s) in: */
  250.     do {
  251.     if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
  252.         PrintGifError();
  253.         break;
  254.     }
  255.     switch (RecordType) {
  256.         case IMAGE_DESC_RECORD_TYPE:
  257.         if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
  258.             PrintGifError();
  259.             exit(-1);
  260.         }
  261.  
  262.         Row = GifFile -> ITop; /* Image Position relative to Screen. */
  263.         Col = GifFile -> ILeft;
  264.         Width = GifFile -> IWidth;
  265.         Height = GifFile -> IHeight;
  266.         GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]:     ",
  267.             PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
  268.         if (GifFile -> ILeft + GifFile -> IWidth > GifFile -> SWidth ||
  269.            GifFile -> ITop + GifFile -> IHeight > GifFile -> SHeight) {
  270.             fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n");
  271.             exit(-2);
  272.         }
  273.         if (GifFile -> IInterlace) {
  274.             /* Need to perform 4 passes on the images: */
  275.             for (Count = i = 0; i < 4; i++)
  276.             for (j = Row + InterlacedOffset[i]; j < Row + Height;
  277.                          j += InterlacedJumps[i]) {
  278.                 GifQprintf("\b\b\b\b%-4d", Count++);
  279.                 if (DGifGetLine(GifFile,
  280.                 &ScreenBuffer[MIN(j, MaximumScreenHeight)][Col],
  281.                 Width) == GIF_ERROR) {
  282.                 PrintGifError();
  283.                 exit(-1);
  284.                 }
  285.             }
  286.         }
  287.         else {
  288.             for (i = 0; i < Height; i++, Row++) {
  289.             GifQprintf("\b\b\b\b%-4d", i);
  290.             if (DGifGetLine(GifFile, &ScreenBuffer[MIN(Row, MaximumScreenHeight)][Col],
  291.                 Width) == GIF_ERROR) {
  292.                 PrintGifError();
  293.                 MaximumScreenHeight = MIN(i - 1, MaximumScreenHeight);
  294.             }
  295.             }
  296.         }
  297.         break;
  298.         case EXTENSION_RECORD_TYPE:
  299.         /* Skip any extension blocks in file: */
  300.         if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
  301.             PrintGifError();
  302.             exit(-1);
  303.         }
  304.         while (Extension != NULL) {
  305.             if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
  306.             PrintGifError();
  307.             exit(-1);
  308.             }
  309.         }
  310.         break;
  311.         case TERMINATE_RECORD_TYPE:
  312.         break;
  313.         default:            /* Should be traps by DGifGetRecordType. */
  314.         break;
  315.     }
  316.     }
  317.     while (RecordType != TERMINATE_RECORD_TYPE);
  318.  
  319.     /* Lets display it - set the global variables required and do it: */
  320.     BackGround = GifFile -> SBackGroundColor;
  321.     ColorMap = (GifFile -> IColorMap ? GifFile -> IColorMap :
  322.                        GifFile -> SColorMap);
  323.     ColorMapSize = 1 << (GifFile -> IColorMap ? GifFile -> IBitsPerPixel :
  324.                         GifFile -> SBitsPerPixel);
  325.  
  326.     gettextinfo(&TextInfo);         /* Save current mode so we can recover. */
  327.  
  328.     initgraph(&GraphDriver, &GraphMode, BGIPath);
  329.     if (graphresult() != grOk)                /* Error occured during init. */
  330.     GIF_EXIT("Graphics System Error, failed to initialize driver.");
  331.  
  332.     if (getmaxcolor() + 1 < ColorMapSize) {
  333.     sprintf(Str, "GIF Image color map (%d) is too big for device (%d).\n",
  334.                           ColorMapSize, getmaxcolor() + 1);
  335.     closegraph();
  336.     GIF_EXIT(Str);
  337.     }
  338.  
  339.     /* Initialize hardware pallete and also select fore/background color.    */
  340.     BackGround = ForeGround = 1;
  341.     Sum = ((int) ColorMap[1].Red) +
  342.       ((int) ColorMap[1].Green) +
  343.       ((int) ColorMap[1].Blue);
  344.     j = k = Sum;
  345.     for (i = 0; i < ColorMapSize; i++) {
  346.     setrgbpalette(i, ColorMap[i].Red >> 2,
  347.              ColorMap[i].Green >> 2,
  348.              ColorMap[i].Blue >> 2);
  349.  
  350.     Sum = ((int) ColorMap[i].Red) +
  351.           ((int) ColorMap[i].Green) +
  352.           ((int) ColorMap[i].Blue);
  353.     if (i != 0 && Sum > j) {            /* Dont use color 0. */
  354.         ForeGround = i;
  355.         j = Sum;
  356.     }
  357.     if (i != 0 && Sum <= k) {            /* Dont use color 0. */
  358.         BackGround = i;
  359.         k = Sum;
  360.     }
  361.     }
  362.  
  363.     DeviceMaxX = getmaxx();            /* Read size of physical screen. */
  364.     DeviceMaxY = getmaxy();
  365.     ScreenWidth = GifFile -> SWidth;
  366.     ScreenHeight = MIN(GifFile -> SHeight, MaximumScreenHeight);
  367.  
  368.     Tone(500, 10);
  369.     DisplayScreen(ScreenBuffer, GifFile);
  370.  
  371.     if (DGifCloseFile(GifFile) == GIF_ERROR) {
  372.     PrintGifError();
  373.     closegraph();
  374.     exit(-1);
  375.     }
  376.  
  377.     closegraph();
  378.  
  379.     textmode(TextInfo.currmode);
  380. }
  381.  
  382. /****************************************************************************
  383. * Routine to be called for the user installed driver:                *
  384. ****************************************************************************/
  385. static int huge detectVGA(void)
  386. {
  387.     return BGIUserDriverMode;
  388. }
  389.  
  390. /****************************************************************************
  391. * Routine to install the user BGI driver information.                *
  392. ****************************************************************************/
  393. static void BGIInstallUserDriver(char *BGIUserDriverNameMode)
  394. {
  395.     char *p;
  396.  
  397.     if ((p = strrchr(BGIUserDriverNameMode, '/')) != NULL ||
  398.     (p = strrchr(BGIUserDriverNameMode, '\\')) != NULL) {
  399.     p[0] = 0;
  400.     BGIPath = strdup(BGIUserDriverNameMode);
  401.     p++;
  402.     }
  403.  
  404.     p = strtok(p, ".");
  405.     BGIUserDriverName = strdup(p);
  406.  
  407.     p = strtok(NULL, ".");
  408.     if (sscanf(p, "%d", &BGIUserDriverMode) != 1 || BGIUserDriverName == NULL)
  409.     GIF_EXIT("User [-u] BGI specification has wrong format.");
  410. }
  411.  
  412. /******************************************************************************
  413. * Given the screen buffer, display it:                          *
  414. * The following commands are available (case insensitive).              *
  415. * 1. Four arrow to move along the screen (only if ScreenBuffer > physical     *
  416. *    screen in that direction.                              *
  417. * 2. C - goto cursor mode - print current color & position in GIF screen      *
  418. *        of the current pixel cursor is on.                      *
  419. * 3. D - zoom out by factor of 2.                          *
  420. * 4. R - redraw current image.                              *
  421. * 5. S - Print Current status/options.                          *
  422. * 6. U - zoom in by factor of 2.                          *
  423. * 7. ' ' - stop drawing current image.                          *
  424. * 8. ESC - to quit.                                  *
  425. ******************************************************************************/
  426. static void DisplayScreen(GifRowType *ScreenBuffer, GifFileType *GifFile)
  427. {
  428.     int DeviceTop, DeviceLeft,   /* Where ScreenBuffer is to mapped to ours. */
  429.     ScreenTop, ScreenLeft,  /* Porsion of ScreenBuffer to start display. */
  430.     XPanning, YPanning,         /* Amount to move using the arrows. */
  431.     GetK, DrawIt = TRUE;
  432.  
  433.     XPanning = DeviceMaxX / 2;
  434.     YPanning = DeviceMaxY / 2;
  435.  
  436.     SetPosition(SET_POSITION_RESET,
  437.         &ScreenLeft, &ScreenTop,
  438.         &DeviceLeft, &DeviceTop,
  439.         0, 0);
  440.  
  441.     do {
  442.     if (DrawIt && !MyKbHit()) {
  443.         DrawScreen(ScreenBuffer, ScreenLeft, ScreenTop,
  444.                      DeviceLeft, DeviceTop);
  445.         Tone(2000, 200);
  446.     }
  447.     DrawIt = TRUE;
  448.     switch (GetK = GetKey()) {
  449.         case 'C':
  450.         DoCursorMode(ScreenBuffer, ScreenLeft, ScreenTop,
  451.                        DeviceLeft, DeviceTop);
  452.         DrawIt = TRUE;
  453.         break;
  454.         case 'D':
  455.         if (ZoomFactor > 1) {
  456.             ZoomFactor >>= 1;
  457.             SetPosition(SET_POSITION_ZOOM_D,
  458.             &ScreenLeft, &ScreenTop,
  459.             &DeviceLeft, &DeviceTop,
  460.             0, 0);
  461.         }
  462.         else {
  463.             Tone(1000, 100);
  464.             DrawIt = FALSE;
  465.         }
  466.         break;
  467.         case 'R':
  468.         break;
  469.         case 'S':
  470.         PrintSettingStatus(GifFile);
  471.         break;
  472.         case 'U':
  473.         if (ZoomFactor < 256) {
  474.             ZoomFactor <<= 1;
  475.             SetPosition(SET_POSITION_ZOOM_U,
  476.             &ScreenLeft, &ScreenTop,
  477.             &DeviceLeft, &DeviceTop,
  478.             0, 0);
  479.         }
  480.         else {
  481.             Tone(1000, 100);
  482.             DrawIt = FALSE;
  483.         }
  484.         break;
  485.         case KEY_ESC:
  486.         break;
  487.         case KEY_LEFT:
  488.         SetPosition(SET_POSITION_PAN,
  489.             &ScreenLeft, &ScreenTop,
  490.             &DeviceLeft, &DeviceTop,
  491.             -XPanning, 0);
  492.         break;
  493.         case KEY_RIGHT:
  494.         SetPosition(SET_POSITION_PAN,
  495.             &ScreenLeft, &ScreenTop,
  496.             &DeviceLeft, &DeviceTop,
  497.             XPanning, 0);
  498.         break;
  499.         case KEY_UP:
  500.         SetPosition(SET_POSITION_PAN,
  501.             &ScreenLeft, &ScreenTop,
  502.             &DeviceLeft, &DeviceTop,
  503.             0, -YPanning);
  504.         break;
  505.         case KEY_DOWN:
  506.         SetPosition(SET_POSITION_PAN,
  507.             &ScreenLeft, &ScreenTop,
  508.             &DeviceLeft, &DeviceTop,
  509.             0, YPanning);
  510.         break;
  511.         default:
  512.         DrawIt = FALSE;
  513.         Tone(800, 100);
  514.         Tone(300, 200);
  515.         break;
  516.     }
  517.     }
  518.     while (GetK != KEY_ESC);
  519. }
  520.  
  521. /******************************************************************************
  522. * Routine to print (in text mode), current program status.              *
  523. ******************************************************************************/
  524. static void PrintSettingStatus(GifFileType *GifFile)
  525. {
  526.     char s[80];
  527.  
  528.     setcolor(ForeGround);
  529.  
  530.     CPrintStr(PROGRAM_NAME, 1);
  531.  
  532.     sprintf(s, "GIF File - %s.", GifFileName);
  533.     CPrintStr(s, 10);
  534.  
  535.     sprintf(s, "Gif Screen Size = [%d, %d]. Contains %d image(s).",
  536.     GifFile -> SWidth, GifFile -> SHeight, ImageNum);
  537.     CPrintStr(s, 20);
  538.  
  539.     if (GifFile -> SColorMap)
  540.     sprintf(s,
  541.         "Has Screen Color map of %d bits. BackGround = [%d, %d, %d].",
  542.         GifFile -> SBitsPerPixel,
  543.         GifFile -> SColorMap[GifFile -> SBackGroundColor].Red,
  544.         GifFile -> SColorMap[GifFile -> SBackGroundColor].Green,
  545.         GifFile -> SColorMap[GifFile -> SBackGroundColor].Blue);
  546.     else
  547.     sprintf(s, "No Screen color map.");
  548.     CPrintStr(s, 30);
  549.  
  550.     if (GifFile -> IColorMap)
  551.     sprintf(s, "Has Image map of %d bits (last image). Image is %s.",
  552.         GifFile -> IBitsPerPixel,
  553.         (GifFile -> IInterlace ? "interlaced" : "non interlaced"));
  554.     else
  555.     sprintf(s, "No Image color map.");
  556.     CPrintStr(s, 40);
  557.  
  558.     CPrintStr("Press anything to continue:", 60);
  559.     MyGetCh();
  560. }
  561.  
  562. /******************************************************************************
  563. * Routine to cprintf given string centered at given Y level, and attr:        *
  564. ******************************************************************************/
  565. static void CPrintStr(char *Str, int y)
  566. {
  567.     setfillstyle(SOLID_FILL, BackGround);
  568.     bar(0, y, textwidth(Str) + 2, y + textheight(Str) + 2);
  569.  
  570.     setcolor(ForeGround);
  571.     outtextxy(1, y + 1, Str);
  572. }
  573.  
  574. /******************************************************************************
  575. * Routine to set the position of Screen in Device, and what porsion of the    *
  576. * screen should be visible:                              *
  577. * MoveX, MoveY are the panning factors (if both zero - initialize).          *
  578. ******************************************************************************/
  579. static void SetPosition(int Why,
  580.                 int *ScreenLeft, int *ScreenTop,
  581.                 int *DeviceLeft, int *DeviceTop,
  582.                 int MoveX,       int MoveY)
  583. {
  584.  
  585.     MoveX /= ZoomFactor;     /* Make sure move move same amount independent. */
  586.     MoveY /= ZoomFactor;               /* of what ZommFactor is. */
  587.  
  588.     /* Figure out position of GIF file in real device X axis: */
  589.     if (ScreenWidth * ZoomFactor <= DeviceMaxX + 1) {
  590.     /* Device is big enough to hold all the image X axis: */
  591.     *ScreenLeft = 0;
  592.     *DeviceLeft = (DeviceMaxX - ScreenWidth * ZoomFactor) / 2;
  593.     }
  594.     else {
  595.     /* Device is too small to hold all the image X axis: */
  596.     switch (Why) {
  597.         case SET_POSITION_RESET:
  598.         *ScreenLeft = 0;
  599.         break;
  600.         case SET_POSITION_ZOOM_U:
  601.         *ScreenLeft += DeviceMaxX / (2 * ZoomFactor);
  602.         break;
  603.         case SET_POSITION_ZOOM_D:
  604.         *ScreenLeft -= DeviceMaxX / (4 * ZoomFactor);
  605.         break;
  606.         case SET_POSITION_PAN:
  607.         if (MoveX != 0) *ScreenLeft += MoveX;
  608.         break;
  609.     }
  610.     if (*ScreenLeft < 0) *ScreenLeft = 0;
  611.     if ((ScreenWidth - *ScreenLeft) * ZoomFactor < DeviceMaxX + 1)
  612.         *ScreenLeft = (ScreenWidth * ZoomFactor -
  613.                         DeviceMaxX + 1) / ZoomFactor;
  614.     *DeviceLeft = 0;
  615.     }
  616.  
  617.     /* Figure out position of GIF file in real device Y axis: */
  618.     if (ScreenHeight * ZoomFactor <= DeviceMaxY + 1) {
  619.     /* Device is big enough to hold all the image Y axis: */
  620.     *ScreenTop = 0;
  621.     *DeviceTop = (DeviceMaxY - ScreenHeight * ZoomFactor) / 2;
  622.     }
  623.     else {
  624.     /* Device is too small to hold all the image Y axis: */
  625.     switch (Why) {
  626.         case SET_POSITION_RESET:
  627.         *ScreenTop = 0;
  628.         break;
  629.         case SET_POSITION_ZOOM_U:
  630.         *ScreenTop += DeviceMaxY / (2 * ZoomFactor);
  631.         break;
  632.         case SET_POSITION_ZOOM_D:
  633.         *ScreenTop -= DeviceMaxY / (4 * ZoomFactor);
  634.         break;
  635.         case SET_POSITION_PAN:
  636.         if (MoveY != 0) *ScreenTop += MoveY;
  637.         break;
  638.     }
  639.     if (*ScreenTop < 0) *ScreenTop = 0;
  640.     if ((ScreenHeight - *ScreenTop) * ZoomFactor < DeviceMaxY + 1)
  641.         *ScreenTop = (ScreenHeight * ZoomFactor -
  642.                          DeviceMaxY - 1) / ZoomFactor;
  643.     *DeviceTop = 0;
  644.     }
  645.  
  646.     /* Make sure the position is on Byte boundary (8 pixels per byte): */
  647.     *DeviceLeft &= 0xfff8;
  648. }
  649.  
  650. /******************************************************************************
  651. * The real drawing of the image is performed here. Few things are taken into  *
  652. * account:                                      *
  653. * 1. The zoom factor. If > 1 each pixel is multiplied this amount vertically  *
  654. *    and horizontally.                                  *
  655. *   The image is drawn from ScreenBuffer ScreenTop/Left in the bottom/right   *
  656. * directions, onto the Device DeviceTop/Left in the bottom/right direction    *
  657. *   Pressing space during drawing will abort this routine.              *
  658. ******************************************************************************/
  659. static void DrawScreen(GifRowType *ScreenBuffer,
  660.         int ScreenLeft, int ScreenTop, int DeviceLeft, int DeviceTop)
  661. {
  662.     int i, j, k, l, CountZoomJ, CountZoomI,
  663.     DeviceWidth, DeviceRight, ScreenBottom;
  664.     unsigned char *ImageBuffer, *p;
  665.     GifPixelType *Line;
  666.  
  667.     /* Make sure we start from scratch. Note cleardevice() uses color 0 even */
  668.     /* if it may be non black.                             */
  669.     cleardevice();
  670.  
  671.     if (getmaxcolor() + 1 == 256) {
  672.     /* Optimize this case - one byte per pixel. */
  673.         DeviceWidth = ScreenWidth * ZoomFactor;
  674.     if (DeviceWidth + DeviceLeft > DeviceMaxX)
  675.         DeviceWidth = DeviceMaxX - DeviceLeft;
  676.         DeviceRight = DeviceLeft + DeviceWidth - 1;
  677.         ScreenBottom = ScreenTop + ScreenHeight - 1;
  678.  
  679.     if ((ImageBuffer = malloc(imagesize(DeviceLeft, DeviceTop,
  680.                         DeviceRight, DeviceTop))) == NULL)
  681.         GIF_EXIT("Failed to allocate memory required, aborted.");
  682.     getimage(DeviceLeft, DeviceTop, DeviceRight, DeviceTop, ImageBuffer);
  683.  
  684.     for (k = DeviceTop; k < DeviceMaxY && ScreenTop <= ScreenBottom;) {
  685.         Line = ScreenBuffer[ScreenTop++];
  686.         p = ImageBuffer + 4;      /* point on first pixel in bitmap. */
  687.         if (ZoomFactor == 1)
  688.         memcpy(p, &Line[ScreenLeft], DeviceWidth);
  689.         else {
  690.         for (i = 0, j = ScreenLeft, CountZoomI = ZoomFactor;
  691.              i < DeviceWidth;
  692.              i++) {
  693.             *p++ = Line[j];
  694.             if (--CountZoomI == 0) {
  695.             CountZoomI = ZoomFactor;
  696.             j++;
  697.             }
  698.         }
  699.         }
  700.  
  701.         /* Abort drawing if space bar was pressed: */
  702.         if (MyKbHit() && GetKey() == ' ') break;
  703.  
  704.         for (i = 0; i < ZoomFactor; i++)
  705.         putimage(DeviceLeft, k++, ImageBuffer, COPY_PUT);
  706.     }
  707.  
  708.     free((char *) ImageBuffer);
  709.     }
  710.     else {
  711.         for (CountZoomJ = ZoomFactor, j = ScreenTop, l = DeviceTop;
  712.          j < ScreenHeight && l <= DeviceMaxY; l++) {
  713.         Line = ScreenBuffer[j];
  714.  
  715.         /* Abort drawing if space bar was pressed: */
  716.         if (MyKbHit() && GetKey() == ' ') break;
  717.  
  718.         for (CountZoomI = ZoomFactor, i = ScreenLeft, k = DeviceLeft;
  719.              i < ScreenWidth && k <= DeviceMaxX;) {
  720.             putpixel(k++, l, Line[i]);
  721.  
  722.             if (!--CountZoomI) {
  723.             /* Go to next column: */
  724.             i++;
  725.             CountZoomI = ZoomFactor;
  726.             }
  727.         }
  728.  
  729.         if (!--CountZoomJ) {
  730.             /* Go to next row: */
  731.             j++;
  732.             CountZoomJ = ZoomFactor;
  733.         }
  734.         }
  735.     }
  736. }
  737.  
  738. /******************************************************************************
  739. * Walks along the current image, while printing pixel value and position.     *
  740. * 4 arrows may be used, and any other key will abort this operation          *
  741. ******************************************************************************/
  742. static void DoCursorMode(GifRowType *ScreenBuffer,
  743.         int ScreenLeft, int ScreenTop, int DeviceLeft, int DeviceTop)
  744. {
  745.     int GetK, DeviceRight, DeviceBottom, x, y, Step;
  746.     GifPixelType Pixel;
  747.     char s[80];
  748.  
  749.     DeviceRight = DeviceLeft + (ScreenWidth - ScreenLeft) * ZoomFactor;
  750.     if (DeviceRight > DeviceMaxX) DeviceRight = DeviceMaxX;
  751.  
  752.     DeviceBottom = DeviceTop + (ScreenHeight - ScreenTop) * ZoomFactor;
  753.     if (DeviceBottom > DeviceMaxY) DeviceBottom = DeviceMaxY;
  754.  
  755.     x = (DeviceLeft + DeviceRight) / 2;
  756.     y = (DeviceTop + DeviceBottom) / 2;
  757.  
  758.     setwritemode(XOR_PUT);
  759.  
  760.     while (TRUE) {
  761.     Pixel = ScreenBuffer[ScreenTop + (y - DeviceTop) / ZoomFactor]
  762.                 [ScreenLeft + (x - DeviceLeft) / ZoomFactor];
  763.     sprintf(s, "Color = %3d [%3d, %3d, %3d], X = %3d, Y = %3d",
  764.         Pixel,
  765.         ColorMap[Pixel].Red,
  766.         ColorMap[Pixel].Green,
  767.         ColorMap[Pixel].Blue,
  768.         (x - DeviceLeft) / ZoomFactor,
  769.         (y - DeviceTop) / ZoomFactor);
  770.  
  771.     setfillstyle(SOLID_FILL, BackGround);
  772.     bar(0, 0, textwidth(s) + 2, textheight(s) + 2);
  773.  
  774.         setcolor(ForeGround);
  775.     outtextxy(1, 1, s);
  776.  
  777.     line(0, y, DeviceMaxX, y);
  778.     line(x, 0, x, DeviceMaxY);
  779.     GetK = GetKey();
  780.     line(0, y, DeviceMaxX, y);
  781.     line(x, 0, x, DeviceMaxY);
  782.  
  783.     Step = 10;
  784.     switch (GetK) {
  785.         case '1':
  786.         GetK = KEY_END;
  787.         break;
  788.         case '2':
  789.         GetK = KEY_DOWN;
  790.         break;
  791.         case '3':
  792.         GetK = KEY_PGDN;
  793.         break;
  794.         case '4':
  795.         GetK = KEY_LEFT;
  796.         break;
  797.         case '6':
  798.         GetK = KEY_RIGHT;
  799.         break;
  800.         case '7':
  801.         GetK = KEY_HOME;
  802.         break;
  803.         case '8':
  804.         GetK = KEY_UP;
  805.         break;
  806.         case '9':
  807.         GetK = KEY_PGUP;
  808.         break;
  809.         default:
  810.         Step = 1;
  811.     }
  812.  
  813.     switch (GetK) {
  814.         case KEY_LEFT:
  815.         x -= Step;
  816.         break;
  817.         case KEY_RIGHT:
  818.         x += Step;
  819.         break;
  820.         case KEY_UP:
  821.         y -= Step;
  822.         break;
  823.         case KEY_DOWN:
  824.         y += Step;
  825.         break;
  826.         case KEY_PGUP:
  827.         y -= Step;
  828.         x += Step;
  829.         break;
  830.         case KEY_PGDN:
  831.         y += Step;
  832.         x += Step;
  833.         break;
  834.         case KEY_HOME:
  835.         y -= Step;
  836.         x -= Step;
  837.         break;
  838.         case KEY_END:
  839.         y += Step;
  840.         x -= Step;
  841.         break;
  842.         default:
  843.         setwritemode(COPY_PUT);
  844.         return;
  845.     }
  846.     if (x < DeviceLeft) x = DeviceLeft;
  847.     if (x >= DeviceRight) x = DeviceRight;
  848.     if (y < DeviceTop) y = DeviceTop;
  849.     if (y >= DeviceBottom) y = DeviceBottom;
  850.     }
  851. }
  852.  
  853. /******************************************************************************
  854. * Return non zero value if at list one character exists in keyboard queue.    *
  855. * This routine emulates kbhit() which do uses stdin and useless for us.       *
  856. ******************************************************************************/
  857. static int MyKbHit(void)
  858. {
  859.     return bioskey(1);
  860. }
  861.  
  862. /******************************************************************************
  863. * Get a key from keyboard directly (bypass stdin as we might redirect it).    *
  864. * This routine emulates getch() which do uses stdin and useless for us.       *
  865. ******************************************************************************/
  866. static int MyGetCh(void)
  867. {
  868.     static int Extended = 0;
  869.     int c;
  870.  
  871.     if (Extended) {
  872.     c = Extended;
  873.     Extended = 0;
  874.     return c;
  875.     }
  876.     else {
  877.     c = bioskey(0);
  878.     if (c & 0x0ff)
  879.         return c;
  880.     else {
  881.         Extended = c >> 8;
  882.         return 0;
  883.     }
  884.     }
  885. }
  886.  
  887. /******************************************************************************
  888. * Get a key from keyboard, and translating operational keys into special      *
  889. * codes (>255).    Lower case characters are upercased.                  *
  890. ******************************************************************************/
  891. static int GetKey(void)
  892. {
  893.     char c;
  894.  
  895.     while (TRUE) switch (c = MyGetCh()) {
  896.     case 0:              /* Extended code - get the next extended char. */
  897.         switch (MyGetCh()) {
  898.         case 75: return KEY_LEFT;
  899.         case 77: return KEY_RIGHT;
  900.         case 72: return KEY_UP;
  901.         case 80: return KEY_DOWN;
  902.         case 71: return KEY_HOME;
  903.         case 79: return KEY_END;
  904.         case 73: return KEY_PGUP;
  905.         case 81: return KEY_PGDN;
  906.         case 83: return KEY_DELETE;
  907.         case 82: return KEY_INSERT;
  908.         }
  909.         break;
  910.     case 8:
  911.         return KEY_BSPACE;
  912.     case 10:
  913.     case 13:
  914.         return KEY_RETURN;
  915.     case 27:
  916.         return KEY_ESC;
  917.     default:
  918.         if (isprint(c)) {
  919.         if (islower(c))
  920.             return toupper(c);
  921.         else
  922.             return c;
  923.         }
  924.         else {
  925.         Tone(800, 100);
  926.         Tone(300, 200);
  927.         }
  928.     }
  929. }
  930.  
  931. /******************************************************************************
  932. * Routine to make some sound with given Frequency, Time milliseconds:          *
  933. ******************************************************************************/
  934. static void Tone(int Frequency, int Time)
  935. {
  936.     if (BeepsDisabled) return;
  937.  
  938.     sound(Frequency);
  939.     delay(Time);
  940.     nosound();
  941. }
  942.